#include <MinMax.h>


using namespace std;

void MinMax::zera(void)
{
    NNOS = 0;
}

MinMax::MinMax()
{
	profundidade = 0;
	func = (FuncaoAvaliacao *)0;
	NNOS = 0;
}

MinMax::~MinMax()
{
	if(func != (FuncaoAvaliacao *)0)
		delete func;
	func = (FuncaoAvaliacao *)0;
}


  void MinMax::setProfundidade ( const int new_var )
  {
      profundidade = new_var;
  }


  void MinMax::setFuncaoAvaliacao (FuncaoAvaliacao* new_var )
  {
      func = new_var;
  }
  
  vector<pair<Tabuleiro, Jogada> > geraFilhos(Tabuleiro tab, Jogador jog)
  {
  
  	vector<pair<Tabuleiro, Jogada> > v;
  	set<Coordenada> s;
  	set<Coordenada>::iterator it;
	pair<Tabuleiro, Jogada> paux;
  	Tabuleiro taux;
  	Jogada jaux;
  	
  	s = tab.jogadasPossiveis(jog);
  	for(it = s.begin(); it != s.end(); ++it)
  	{
  		taux = tab;
  		jaux.setCoordenada(*it);
  		taux.joga(*it, jog);
  		
		paux.first = taux;
		paux.second = jaux;
		v.push_back(paux);
  	}
  
	return v;
  }
  
  Jogada MinMax::executa(Tabuleiro tab, const Jogador& jog,  const Jogador& adv,
                         int alfa, int beta, int depth)
  {
  	Jogada jogada;
  	Jogada outraJogada;
  	vector<pair<Tabuleiro, Jogada> > listaFilhos;
  	vector<pair<Tabuleiro, Jogada> >::iterator it;
  	int aux;
	int pa;
	int pb;
	
	NNOS++;

	if((depth % 2) == 0)
	{

		pa = alfa;
		listaFilhos = geraFilhos(tab, jog);
		jogada.setVal(-INF);

		if(depth + 1 == profundidade)
		{
			if(listaFilhos.empty())
			{
				qDebug() << "Sem filhos";
				jogada.setVal(func->avalia(tab, jog));
				jogada.setCoordenada(make_pair(-1,-1));
			}else
			{
				for(it = listaFilhos.begin(); it != listaFilhos.end(); ++it)
				{	
					NNOS++;
					aux = func->avalia(it->first, jog);
					if(aux > jogada.getVal())
					{
						if(aux > pa)
							pa = aux;
						jogada.setVal(aux);
						jogada.setCoordenada(it->second.getCoordenada());
					}

					//Corte alfa.beta
					if(beta < jogada.getVal())
						break;
				}
			}
			
		}
		else
		{
			if(listaFilhos.empty())
			{
				qDebug() << "Sem filhos";
				jogada.setVal(func->avalia(tab,jog));
				jogada.setCoordenada(make_pair(-1,-1));
			}
			else
			{	
				for(it = listaFilhos.begin(); it != listaFilhos.end(); ++it)
				{	
					outraJogada = executa(it->first, jog, adv, pa, beta ,depth+1);
					if(outraJogada.getVal() > jogada.getVal())
					{
						if(outraJogada.getVal() > pa)
							pa = outraJogada.getVal();
						jogada.setVal(outraJogada.getVal());
						jogada.setCoordenada(it->second.getCoordenada());
					}
					if(beta < jogada.getVal())
						break;
				}
			}
		}
	}
	else
	{
		pb = beta;
		jogada.setVal(INF);
		listaFilhos = geraFilhos(tab, adv);
		
		if(depth + 1 == profundidade)
		{
			if(listaFilhos.empty())
			{
				jogada.setVal(func->avalia(tab,jog));
				jogada.setCoordenada(make_pair(-1,-1));
			}
			else
			{
				for(it = listaFilhos.begin(); it != listaFilhos.end(); ++it)
				{	
					NNOS++;
					aux = func->avalia(it->first, jog);
					if(aux < jogada.getVal())
					{
						if(aux < pb)
							pb = aux;
						jogada.setVal(aux);
						jogada.setCoordenada(it->second.getCoordenada());
					}
					if(alfa > jogada.getVal())
						break;
				}
			}
		}
		else
		{
			if(listaFilhos.empty())
			{
				qDebug() << "Sem filhos";
				jogada.setVal(func->avalia(tab,jog));
				jogada.setCoordenada(make_pair(-1,-1));
			}
			else
			{
				for(it = listaFilhos.begin(); it != listaFilhos.end(); ++it)
				{	
					outraJogada = executa(it->first, jog, adv, alfa, pb, depth+1);
					if(outraJogada.getVal() < jogada.getVal())
					{
						if(outraJogada.getVal() < pb)
							pb = outraJogada.getVal();

						jogada.setVal(outraJogada.getVal());
						jogada.setCoordenada(it->second.getCoordenada());
					}
					if(alfa > jogada.getVal())
						break;
				}
			}
		}
	}
	
	return jogada;
  }

